package yao.guava.optional;

import org.junit.Test;

import com.google.common.base.Optional;

/**
 * 
 * 相比默默地接受null，使用快速失败操作拒绝null值对开发者更有帮助。
 * 不使用null 原因：null语义是模糊的
 * @author chenyao
 *
 */
public class OptionalTest {
	/**
	 * TIP
	 * 1.不要在Set中使用null，或者把null作为map的键值。使用特殊值代表null会让查找操作的语义更清晰。
	 * 2.如果你想把null作为map中某条目的值，更好的办法是 不把这一条目放到map中，而是单独维护一个”值为null的键集合” (null keys)。
	 * 3.Map 中对应某个键的值是null，和map中没有对应某个键的值，是非常容易混淆的两种情况。因此，最好把值为null的键分离开，并且仔细想想，null值的键在你的项目中到底表达了什么语义。
	 */
	/**
	 * 使用Optional的意义
	 * 1.使用Optional除了赋予null语义，增加了可读性，最大的优点在于它是一种傻瓜式的防护。
	 * Optional迫使你积极思考引用缺失的情况，因为你必须显式地从Optional获取引用。直接使用null很容易让人忘掉某些情形
	 * 如同输入参数，方法的返回值也可能是null。
	 * 和其他人一样，你绝对很可能会忘记别人写的方法method(a,b)会返回一个null，就好像当你实现method(a,b)时，也很可能忘记输入参数a可以为null。
	 * 将方法的返回类型指定为Optional，也可以迫使调用者思考返回的引用缺失的情形。
	 */
	
	/**
	 * 其他处理null的便利方法
	 * 当你需要用一个默认值来替换可能的null，请使用Objects.firstNonNull(T, T) 方法。
	 * 如果两个值都是null，该方法会抛出NullPointerException。Optional也是一个比较好的替代方案，例如：Optional.of(first).or(second).
	 * 还有其它一些方法专门处理null或空字符串：emptyToNull(String)，nullToEmpty(String)，isNullOrEmpty(String)。
	 * 我们想要强调的是，这些方法主要用来与混淆null/空的API进行交互。
	 * 当每次你写下混淆null/空的代码时，Guava团队都泪流满面。（好的做法是积极地把null和空区分开，以表示不同的含义，在代码中把null和空同等对待是一种令人不安的坏味道。
	 */
	
	@Test
	public void testOptional() {
		//大多数情况下，开发人员使用null表明的是某种缺失情形：可能是已经有一个默认值，或没有值，或找不到值。例如，Map.get返回null就表示找不到给定键对应的值。
		//Guava用Optional<T>表示可能为null的T类型引用。一个Optional实例可能包含非null的引用（我们称之为引用存在），也可能什么也不包括（称之为引用缺失）
		//它从不说包含的是null值，而是用存在或缺失来表示。但Optional从不会包含null值引用。
		Optional<Integer> num = Optional.of(5);	//创建指定引用的Optional实例，若引用为null则快速失败
		num.isPresent();	//如果Optional包含非null的引用（引用存在），返回true
		num.get();	//返回Optional所包含的引用，若引用缺失，则抛出java.lang.IllegalStateException
		num.orNull(); //返回Optional所包含的引用，若引用缺失，返回null
		num.or(0);	//返回Optional所包含的引用，若引用缺失，返回指定的值
		num.asSet();	//返回Optional所包含引用的单例不可变集，如果引用存在，返回一个只有单一元素的集合，如果引用缺失，返回一个空集合
		
		Optional<Object> absent = Optional.absent();	//创建引用缺失的Optional实例
		System.out.println(absent.isPresent());
		
		Optional.fromNullable(null);	//创建指定引用的Optional实例，若引用为null则表示缺失
	}
}
